#ifndef TIEC_COMPONENT_H
#define TIEC_COMPONENT_H

#include "data.h"
#include "foundation.h"

#define COMPONENT_NAME(cls) kComponent##cls
#define DECL_COMPONENT_TYPE(cls) String cls::getType() { \
  return COMPONENT_NAME(cls);                            \
}
#define DECL_COMPONENT_NAME(cls) static constexpr const char* COMPONENT_NAME(cls) = #cls;
#define DEF_COMPONENT_FACTORY(cls) static cls* instance(const PTR<Context>& context);
#define DECL_COMPONENT_FACTORY(cls) cls* cls::instance(const PTR<Context>& context) { \
  cls* instance = context->get<cls>(COMPONENT_NAME(cls));                             \
  if (instance == nullptr) {                                                          \
    instance = new cls;                                                               \
    context->add(instance);                                                           \
  }                                                                                   \
  return instance;                                                                    \
}
#define DECL_COMPONENT_FACTORY2(cls, parent_cls) parent_cls* parent_cls::instance(const PTR<Context>& context) { \
  parent_cls* instance = context->get<parent_cls>(COMPONENT_NAME(parent_cls));                     \
  if (instance == nullptr) {                                                          \
    instance = new cls;                                                               \
    context->add(instance);                                                           \
  }                                                                                   \
  return instance;                                                                    \
}

namespace NS_TIEC {
  /// 编译器组件
  class Component {
  public:
    /// 组件类型
    /// \return 组件的名称(type)
    virtual String getType() = 0;
  };

  /// 编译器组件上下文
  class Context {
  public:
    ~Context();

    /// 获取上下文中指定编译器组件
    /// \tparam T 组件类型
    /// \param type 组件名称
    /// \return 对应的编译器组件，如果找不到则返回空指针
    template<class T>
    T* get(const String& type) {
      auto it = components_.find(type);
      if (it == components_.end()) {
        return nullptr;
      }
      return reinterpret_cast<T*>(it->second);
    }

    /// 获取上下文中指定编译器组件，如果没有则执行创建
    /// \tparam T 组件类型
    /// \param type 组件名称
    /// \param supplier 创建组件的函数
    /// \return 对应的编译器组件，如果找不到则返回空指针
    template<class T>
    T* getOrCreate(const String& type, FUNCTION(T*()) supplier) {
      auto it = components_.find(type);
      if (it == components_.end()) {
        T* instance = supplier();
        components_[instance->getType()] = instance;
        return instance;
      }
      return reinterpret_cast<T*>(it->second);
    }

    /// 在上下文中注册一个编译器组件
    /// \tparam T 组件类型
    /// \param component 编译器组件
    template<class T>
    void add(T* component) {
      components_[component->getType()] = component;
    }

  private:
    HashMap<String, Component*> components_;
  };

  /// 编译选项
  class Options : public Component {
  public:
    static Options kDefault;

    /// 默认包名
    String namespace_;
    /// 输出路径
    String output_path_;
    /// 行号表输出路径
    String line_map_path;
    /// debug工具包输出路径
    String debug_tool_path_;
    /// debug目标平台
    String debug_platform_;
    /// 是否debug模式
    bool debug_{false};
    /// 是否进行代码优化
    bool optimize_{false};
    /// 是否进行硬输出，所有用到的文件都拷贝到输出目录，而不是使用地址引用
    bool hard_mode_{false};
    /// 是否支持嵌入式代码
    bool enable_code_{true};
    /// 是否支持顶级语句，即在类之外编写语句
    bool enable_top_statements_{true};
    /// 泛型是否使用生成新类的方式进行实现
    bool template_type_newclass_{false};
    /// 日志输出级别
    LogLevel log_level_;

    String getType() override;

    DEF_COMPONENT_FACTORY(Options)
  };

  /// Name对象池组件
  class NamePool : public Component {
  public:
    PTR<Name> error_;
    PTR<Name> tiecode_basic_;
    PTR<Name> this_;
    PTR<Name> super_;
    PTR<Name> code_this_;
    PTR<Name> string_;
    PTR<Name> int_;
    PTR<Name> long_;
    PTR<Name> float_;
    PTR<Name> double_;
    PTR<Name> bool_;
    PTR<Name> char_;
    PTR<Name> byte_;
    PTR<Name> variant_;
    PTR<Name> file_;
    PTR<Name> color_;
    PTR<Name> array_access_;
    PTR<Name> array_assign_;
    PTR<Name> equals_;
    PTR<Name> question_;
    PTR<Name> plus_;
    PTR<Name> minus_;
    PTR<Name> mul_;
    PTR<Name> div_;
    PTR<Name> xor_;
    PTR<Name> mod_;
    PTR<Name> double_equals_;
    PTR<Name> not_equals_;
    PTR<Name> less_;
    PTR<Name> greater_;
    PTR<Name> less_equals_;
    PTR<Name> greater_equals_;

    NamePool();
    PTR<Name> getName(const String& str);

    String getType() override;
    DEF_COMPONENT_FACTORY(NamePool)
  private:
    HashMap<String, PTR<Name>> name_map_;
  };

  /// 消息收集器
  class Messages : public Component {
  public:
    /// 收集提示信息级别的日志
    /// \param message 信息文本内容
    virtual void info(const String& message) = 0;

    /// 收集警告级别的日志
    /// \param message 信息文本内容
    virtual void warning(const String& message) = 0;

    /// 收集错误级别的日志
    /// \param message 信息文本内容
    virtual void error(const String& message) = 0;

    /// 收集诊断信息
    /// \param diagnostic 诊断信息
    virtual void diagnostic(Diagnostic& diagnostic) = 0;

    /// 获取收集到的错误数量
    virtual UInt32 errorCount() = 0;

    /// 获取收集到的警告数量
    virtual UInt32 warningCount() = 0;

    String getType() override;
  };

  /// 诊断信息处理组件
  class DiagnosticHandler : public Component {
  public:
    /// 输出诊断信息
    /// \param diagnostic 诊断信息详情
    virtual void report(Diagnostic& diagnostic) = 0;

    String getType() override;
  };

  DECL_COMPONENT_NAME(Options)
  DECL_COMPONENT_NAME(NamePool)
  DECL_COMPONENT_NAME(Messages)
  DECL_COMPONENT_NAME(DiagnosticHandler)
}
#endif //TIEC_COMPONENT_H
